package com.howso.cloud.common.crypto;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

/**
 * key加密
 */
@Slf4j
public class KeyCryptoUtil {
    
    private static KeyPair keyPair;
    
    /**
     * 指定加密算法RSA非对称加密
     *
     */
    private static final String RSA = "key.rsa";
    
    /**
     * 指定RSA非对称算法/ECB模式/填充方式
     *
     */
    private static final String RSA_CIPHER = "key.rsa.cipher";
    private static final String ROOT_KEY_DEFAULT = "key.root.key";
    private static final String WORK_KEY_DEFAULT = "key.work.key";
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 56;
    /**
     * 初始化密码器
     *
     */
    static  {
        KeyPairGenerator keyPairGenerator = null;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(SettingUtils.get(RSA));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        keyPair = keyPairGenerator == null ? null : keyPairGenerator.generateKeyPair();
    }
    
    /**
     * 获取私钥（String形式）
     *
     * @return java.lang.String
     */
    protected static String getPrivateKeyStr() {
        return Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
    }
    
    /**
     * 获取公钥（String形式）
     *
     * @return java.lang.String
     */
    protected  static String getPublicKeyStr() {
        return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
    }
    
    /**
     * 把String的公钥转换为PublicKey
     *
     * @param key 字符串类型的公钥
     * @return java.security.PublicKey
     */
    protected  static PublicKey toPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory kf = KeyFactory.getInstance(SettingUtils.get(RSA));
        return kf.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(key)));
    }
    
    /**
     * 把String的私钥转换为PrivateKey
     *
     * @param key 字符串类型的私钥
     * @return java.security.PrivateKey
     */
    protected  static PrivateKey toPrivateKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory kf = KeyFactory.getInstance(SettingUtils.get(RSA));
        return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key)));
    }
    
    /**
     * 使用公钥对数据进行加密
     *
     * @param content 原数据
     * @param publicKey 公钥（字符串）
     * @return java.lang.String
     */
    protected static String encrypt(String content, String publicKey) {
        String result = null;
        try {
            byte[] dataByte = content.getBytes(StandardCharsets.UTF_8);
            Cipher cipher = Cipher.getInstance(SettingUtils.get(RSA_CIPHER));
            cipher.init(Cipher.ENCRYPT_MODE, toPublicKey(publicKey));
            result = Base64.getEncoder().encodeToString(cipher.doFinal(dataByte));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }
    
    /**
     * 使用私钥对密文进行解密
     *
     * @param cipherStr 密文
     * @param privateKey 私钥（字符串）
     * @return java.lang.String
     */
    protected static String decrypt(String cipherStr, String privateKey) {
        String result = null;
        try {
            Cipher cipher = Cipher.getInstance(SettingUtils.get(RSA_CIPHER));
            cipher.init(Cipher.DECRYPT_MODE, toPrivateKey(privateKey));
            result =  new String(cipher.doFinal(Base64.getDecoder().decode(cipherStr)), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return result;
    }
    
    /**
     * 组装私钥
     * @param encryptedData
     * @return
     */
    protected static String priKeyAssemble(String[] encryptedData){
         List<String> list=new ArrayList<>();
        Arrays.stream(encryptedData).forEach(str ->{
            list.add(DataCryptoUtil.decrypt(str,getRootKey()));
        });
        return StringUtils.join(list,"");
    }
    
    /**
     * 切割私钥
     * @param data
     * @return
     */
    protected static String[] priKeySection(String data){
        String[] result = new String[0];
        int inputLen = data.length();
        int offSet = 0;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                result=insert(result,DataCryptoUtil.encrypt(data.substring(offSet,offSet+MAX_DECRYPT_BLOCK),getRootKey()));
            } else {
                result=insert(result,DataCryptoUtil.encrypt(data.substring(offSet, inputLen),getRootKey()));
            }
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        return result;
    }
    
    protected static String[] insert(String[] strings, String string) {
        if (strings == null) {
            strings = new String[0];
        }
        if (string.isEmpty()) {
            return null;
        }
        String[] resultString = new String[strings.length + 1];
        for (int i = 0; i < strings.length; i++) {
            resultString[i] = strings[i];
        }
        resultString[strings.length] = string;
        return resultString;
    }
    /**
     * 获取data加密用的默认key
     * @return
     */
    protected static String getRootKey()  {
        try {
            return CryptoStringUtil.uncompress(SettingBurstUtils.get(ROOT_KEY_DEFAULT))+CryptoStringUtil.uncompress(SettingUtils.get(ROOT_KEY_DEFAULT));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    protected static String getWorkKeyCiphertext()  {
        return SettingBurstUtils.get(WORK_KEY_DEFAULT);
    }
    
}
